use crypto;
use crypto::buffer::ReadBuffer;
use crypto::buffer::WriteBuffer;
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use pinyin::ToPinyin;
use rand::RngCore;
use rand::rngs::OsRng;
use regex::Regex;
use serde_json::Value;
use serde_json::json;

use super::my_err::MyErr;

static CHARS: &'static [u8] = b"0123456789abcdef";

/// 程序专用的md5
#[allow(dead_code)]
pub fn app_md5(str: &str) -> String {
    if str.is_empty() {
        // return Md5(Md5("Admin#2024!01&10") + "-MaLaoygBuHMLB")

        let mut s = md5("Admin#2024!01&10");
        s.push_str("-MaLaoygBuHMLB");
        md5(&s)
    } else {
        // return Md5(Md5(str) + "-MaLygHMLB")

        let mut s = md5(str);
        s.push_str("-MaLaoygBuHMLB");
        md5(&s)
    }
}

/// 通用MD5算法
pub fn md5(str: &str) -> String {
    let mut md5 = crypto::md5::Md5::new();
    md5.input_str(str);
    return md5.result_str();
}

/// 通用MD5算法。得到字节数组
pub fn md5_to_vec(str: &str) -> Vec<u8> {
    // 计算MD5哈希值，返回Digest结构体
    let digest = md5::compute(str);

    // // 获取128位（16字节）的二进制字节数组
    // let md5_bytes: [u8; 16] = digest.0;
    
    // println!("原始数据: {}", data);
    // println!("MD5十六进制: {:x}", digest);
    // println!("MD5字节数组: {:?}", md5_bytes);
    // println!("字节数组长度: {} 字节", md5_bytes.len());
    
    // // 可以进一步处理字节数组
    // let hex_string = md5_bytes.iter()
    //     .map(|byte| format!("{:02x}", byte))
    //     .collect::<String>();
    // println!("手动拼接的十六进制: {}", hex_string);

    digest.to_vec()
} 

/// 通用sha1算法
pub fn sha1(str: &str) -> String {
    let mut sha1 = crypto::sha1::Sha1::new();
    sha1.input_str(str);
    return sha1.result_str();
}

/// 通用sha256算法
pub fn sha256(str: &str) -> String {
    let mut sha256 = Sha256::new();
    sha256.input_str(str);
    return sha256.result_str();
}

/// 通用sha256算法
pub fn sha256_binary(input: &[u8]) -> String {
    let mut sha256 = Sha256::new();
    sha256.input(input);
    return sha256.result_str();
}

/// hmac_sha256 算法
pub fn hmac_sha256(key: &str, str: &str) -> String {
    let mut hmac = Hmac::new(Sha256::new(), key.as_bytes());
    hmac.input(str.as_bytes());
    let rs = hmac.result();

    let mut v = Vec::with_capacity(rs.code().len() * 2);
    for &byte in rs.code().iter() {
        v.push(CHARS[(byte >> 4) as usize]);
        v.push(CHARS[(byte & 0xf) as usize]);
    }

    unsafe { String::from_utf8_unchecked(v) }
}

/// hmac_sha256 算法
pub fn hmac_sha256_base64(key: &str, str: &str) -> String {
    let mut hmac = Hmac::new(Sha256::new(), key.as_bytes());
    hmac.input(str.as_bytes());
    let rs = hmac.result();

    base64_encode_vec(rs.code())
}

/// 把 base64编码格式的字符串解码成 u8 数组
pub fn base64_decode(str: &str) -> Result<Vec<u8>, MyErr> {
    let rs = rbase64::decode(str);
    match rs {
        Ok(arry) => Ok(arry),
        Err(_) => Err(MyErr::Msg("对字符串进行base64解码的时候发生了错误！".to_string())),
    }
}

/// 把字符串用 base64 方法加密
#[allow(dead_code)]
pub fn base64_encode(str: &str) -> String {
    rbase64::encode(str.as_bytes())
}

#[allow(dead_code)]
pub fn base64_encode_vec(data: &[u8]) -> String {
    rbase64::encode(data)
}

/// 使用 aes256 cbc pkcs#7 方式解密文本内容
/// text_data： 待解密的文本内容，提前经过 base64 解码
/// key_data: 密钥，提前经过 base64 解码
/// ```
/// let msg_data = util_string::base64_decode(str)?; // 对消息文本做base64解码。得到 u8 数组数据
/// let key_data = util_string::base64_decode(format!("{}=", self.encoding_aes_key).as_str())?; // 对密钥key做base64解码。得到 u8 数组数据
/// let dec_data = util_string::aes256_cbc_decrypt(msg_data, key_data)?;
///
/// let dstr = String::from_utf8_lossy(&dec_data.as_slice());
/// log::info!("解密后的字符串:[{}]", dstr);
///
/// ```
pub fn aes256_cbc_decrypt(text_data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, MyErr> {
    let mut iv: [u8; 16] = [0; 16];

    let mut ran = OsRng::default();
    ran.fill_bytes(&mut iv);

    //text_data.iter().for_each(|v|print!("{} ", v));

    //println!("需要解密的数据长度:{}", text_data.len());
    //println!("key的数据长度:{}", key_data.len());

    let mut decryptor = crypto::aes::cbc_decryptor(crypto::aes::KeySize::KeySize256, key_data, &iv, crypto::blockmodes::PkcsPadding);

    let mut final_result = Vec::<u8>::new();
    let mut read_buffer = crypto::buffer::RefReadBuffer::new(text_data);
    let mut buffer = [0; 1024];
    let mut write_buffer = crypto::buffer::RefWriteBuffer::new(&mut buffer);

    loop {
        // eof: false 必须为 false; 这里设置为 true 的情况下，在微信中会出异常。导致部分消息解密失败
        if let Ok(result) = decryptor.decrypt(&mut read_buffer, &mut write_buffer, false) {
            final_result.extend(write_buffer.take_read_buffer().take_remaining().iter().map(|&i| i));
            match result {
                crypto::buffer::BufferResult::BufferUnderflow => break,
                crypto::buffer::BufferResult::BufferOverflow => {}
            }
        } else {
            return Err(MyErr::Msg("aes 解密失败！".to_string()));
        }
    }

    Ok(final_result)
}

/// 判断字符串是否是空白字符串
/// "" -> true
/// "  " -> true
/// "  a " -> false
pub fn is_empty(str: &str) -> bool {
    if str.trim().len() > 0 { false } else { true }
}

/// 查找字符出现的次数
pub fn find_char_count(str: &str, c: char) -> i32 {
    let mut count = 0;
    for s in str.chars() {
        if s == c {
            count = count + 1;
        }
    }
    count
}

/// 拼接 serde_json::Value 类型的 vec ，使用 spc 字符连接
pub fn jvec_to_string(list: &Vec<Value>, spc: &str) -> String {
    let mut text = String::from("");
    for v in list {
        text.push_str(format!("{}{}", v, spc).as_str());
    }

    // 字符串尝试删除后缀是 spc 的字符，如果有则删除并返回新字符串，没有则返回原始字符串
    text.trim_end_matches(spc).to_string()
}

/// 拼接 i64 数组，使用 spc 字符链接
/// ```
/// let array = vec![23,12,41,2,1];
/// i64s_to_str(array, ",") -> "23,12,41,2,1"
/// ```
#[allow(dead_code)]
pub fn i64s_to_str(array: Vec<i64>, spc: &str) -> String {
    let mut text = String::from("");
    for v in array {
        text.push_str(format!("{}{}", v, spc).as_str());
    }

    // 字符串尝试删除后缀是 spc 的字符，如果有则删除并返回新字符串，没有则返回原始字符串
    text.trim_end_matches(spc).to_string()
}

/// 拼接 i64 数组，使用 spc 字符链接
/// ```
/// let array = vec![23,12,41,2,1];
/// i64s_to_str(array, ",") -> "23,12,41,2,1"
/// ```
#[allow(dead_code)]
pub fn i64s_to_ji64(array: Vec<i64>) -> Vec<Value> {
    let mut data: Vec<Value> = Vec::new();
    for item in array {
        let v = serde_json::to_value(item).unwrap_or_default();
        data.push(v);
    }
    data
}

/// 字符串转 Vec<i32>
#[allow(dead_code)]
pub fn str_to_ver_ji32(str: &str) -> Vec<Value> {
    str.split(",").into_iter().map(|v| json!(v.parse::<i32>().unwrap_or_default())).collect()
}

/// 字符串转 Vec<i64>
#[allow(dead_code)]
pub fn str_to_ver_ji64(str: &str) -> Vec<Value> {
    str.split(",").into_iter().map(|v| json!(v.parse::<i64>().unwrap_or_default())).collect()
}

/// 字符串转 Vec<String>
#[allow(dead_code)]
pub fn str_to_vec_jstr(str: &str) -> Vec<Value> {
    str.split(",").into_iter().map(|v| json!(v.parse::<i32>().unwrap_or_default())).collect()
}

/// 驼峰命名转蛇形命名
pub fn camel_to_snake(str: &str) -> String {
    let mut s = String::from("");
    for (_i, c) in str[..].char_indices() {
        if c >= 'A' && c <= 'Z' {
            s.push('_');
            s.push(c);
        } else {
            s.push(c);
        }
    }
    s.to_lowercase().trim_start_matches("_").to_string()
}

/// 获取汉字的拼音
pub fn chs_to_py(str: &str) -> String {
    let mut py = String::new();
    for pinyin in str.to_pinyin() {
        if let Some(pinyin) = pinyin {
            //print!("{} ", pinyin.first_letter());
            py.push_str(&pinyin.first_letter());
        }
    }
    return py;
}

/// 判断字符串是否手机号
#[allow(dead_code)]
pub fn is_phone(s: &str) -> bool {
    if let Ok(re) = Regex::new("^1[3|4|5|6|7|8|9][0-9]\\d{8}$") {
        re.is_match(s)
    } else {
        false
    }
}

/// 判断字符串是否车牌号
#[allow(dead_code)]
pub fn is_plate_no(s: &str) -> bool {
    // 普通车牌号
    if let Ok(re1) =
        Regex::new("^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][a-zA-Z]{1}[0-9a-hj-np-zA-HJ-NP-Z]{5}$")
    {
        // 新能源车牌号（小型车）
        if let Ok(re2) = Regex::new(
            "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][a-zA-Z]{1}[abcdefghjkABCDEFGHJK]{1}[0-9a-hj-np-zA-HJ-NP-Z]{5}$",
        ) {
            // 新能源车牌号（大型车）
            if let Ok(re3) = Regex::new(
                "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][a-zA-Z]{1}[0-9a-hj-np-zA-HJ-NP-Z]{5}[abcdefghjkABCDEFGHJK]{1}$",
            ) {
                if re1.is_match(s) {
                    true
                } else if re2.is_match(s) {
                    true
                } else if re3.is_match(s) {
                    true
                } else {
                    false
                }
            } else {
                false
            }
        } else {
            false
        }
    } else {
        false
    }
}

/// 判断字符串是否身份证号
pub fn is_idcard(idcard: &str) -> bool {
    if idcard.len() != 18 {
        return false;
    }

    let regex = r"^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$";

    if let Ok(re) = Regex::new(regex) {
        if re.is_match(idcard) {
            let factor = [7u32, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
            let mut sum = 0;
            let mut chars = idcard.chars();
            for i in 0..17 {
                let v = chars.next().unwrap_or_default();
                sum += (v as u32 - 48) * factor[i];
            }
            let parity = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"];
            //let c = parity[sum as usize % 11];
            //println!("c:{}  idcard[17..]:{}", c, idcard[17..].to_string());
            idcard[17..] == *parity[sum as usize % 11]
        } else {
            false
        }
    } else {
        false
    }
}

/// 通过身份证号获取生日，生日格式（2002-05-02）
#[allow(dead_code)]
pub fn get_birthday_by_idcard(idcard: &str) -> Result<String, MyErr> {
    if is_idcard(idcard) {
        let year = &idcard[6..10];
        let month = &idcard[10..12];
        let day = &idcard[12..14];
        Ok(format!("{}-{}-{}", year, month, day))
    } else {
        Err(MyErr::Msg("错误的身份证号！".to_string()))
    }
}

/// 通过身份证号判断性别
/// 返回值 1:男， 2：女
#[allow(dead_code)]
pub fn get_sex_by_idcard(idcard: &str) -> Result<usize, MyErr> {
    if is_idcard(idcard) {
        let sex = &idcard[16..17].parse::<usize>().unwrap_or(1);
        println!("\n\n sex: {}", sex);
        if sex % 2 == 0 { Ok(2) } else { Ok(1) }
    } else {
        Err(MyErr::Msg("错误的身份证号！".to_string()))
    }
}

/// 判断组织机构代码是否合法
pub fn is_organization_code(text: &str) -> bool {
    if text.len() != 18 {
        return false;
    }

    // 最简单正则判断通过后再进行校验码判断
    if let Ok(re) = Regex::new("^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$") {
        if re.is_match(text) {
            // 如果正则通过，则进行校验码判断
            let code_array = [
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P',
                'Q', 'R', 'T', 'U', 'W', 'X', 'Y',
            ];
            let weight = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];

            // 获取最后一位校验码
            let cs: Vec<_> = text.chars().collect();
            if let Some(check) = cs.get(17) {
                let mut sum = 0;
                for i in 0..17 {
                    let c = cs.get(i).unwrap_or(&'0');
                    // let x = code_array.binary_search(&c).unwrap_or_default();
                    // let w = weight[i];
                    sum += code_array.binary_search(&c).unwrap_or_default() * weight[i];
                    //println!("c:{} x:{:?}", c, x);
                }

                let index = 31 - sum % 31;
                let check2 = code_array[index];
                check.eq(&check2)
            } else {
                false
            }
        } else {
            false
        }
    } else {
        false
    }
}
